// 引入fs的promise形式，避免使用回调
let  fsPromise  = require( 'fs/promises');
let path = require('path')
//判断是否是0x00 00 00 01
function FindStartCode2(buffer = Buffer.from([])){
	if(!buffer.length){
		return false
	}
	if(buffer[0] !=0 || buffer[1] != 0 || buffer[2] != 1){
		return false
	}else{
		return true
	}
}

//判断是否是0x00 00 00 01
function FindStartCode3(buffer = Buffer.from([])){
	if(!buffer.length){
		return false
	}
	if(buffer[0] !=0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 1){
		return false
	}else{
		return true
	}
}

// 获取文件基本信息，使用同步的方法，成功时将会打印文件信息并返回，错误时返回空对象
//目的是为了获取文件大小，便于下一步管理buffer
async function getFileInfoAsync(filename = ''){
	try{
		let stat = await	fsPromise.stat(filename)
		console.log('fileInfo:',stat)
		return stat
	}
	catch(err){
		return {}
	}
		
}


//h264 avvc格式转为annexb格式，便于后续解码器处理 输入必须为h264流，不能是MP4chunk,因为chunk之间有间隙，不一定连续
// 送进去，只要返回一个完整的nalu序列(sps+pps+I)就行了
function h264_mp4toannexb(bufferStream = new Buffer() , NaluHeaderLength = 4){
	let offset = 0  //定义一个游标
	let sps_length = 0;
	let pps_length = 0;
	let data_length = 0;
	if(bufferStream.length == 0){
		return false
	}
	const start_code  = Buffer.from([0x00,0x00,0x00,0x01])
	const start_code_short = Buffer.from([0x00, 0x00, 0x01])
	let newBufferStream = Buffer.from([])
	const PB_header = Buffer.from([0x01,0x9a,0x24,0x18])
	// 长度不知 需要计算出来
	// 根据nalu_header长度，计算出大小
	if(NaluHeaderLength == 4){
		
		while(offset<bufferStream.length-4){
			// 这里是明确知道,这是帧开头,并且有4个字段的长度描述信息
			// avcc是没有分隔符的,所有描述信息都在moov表中
		   // 这里有2种情况，关键帧，前面带sps,pps，接着是data,不是关键帧，直接是length + data
			let naluType = bufferStream[offset + 4] % 16
			console.log('naluType:',naluType, 'type字段值',bufferStream[offset + 4])
			if(naluType === 7){
				//如果是SPSnalu
				sps_length = bufferStream.slice(offset,offset + 4).readUInt32BE(0)
				offset = offset + 4
				let spsNalu = bufferStream.slice(offset, offset + sps_length)
				console.log('sps_length:',sps_length, spsNalu)
				offset = sps_length + offset
				

				pps_length = bufferStream.slice(offset,offset + 4).readUInt32BE(0)
				offset = offset + 4
				let ppsNalu = bufferStream.slice(offset, offset+ pps_length)
				console.log('pps_length:',pps_length,ppsNalu)
				offset = offset + pps_length

				data_length = bufferStream.slice(offset,offset + 4).readUInt32BE(0)
				offset = offset + 4
				if(offset + data_length < bufferStream.length){
					//没到buffer结尾
					let IdrNalu = bufferStream.slice(offset, offset + data_length)
					offset = offset + data_length
					console.log('data_length:',data_length)
					console.log('data_offset:',offset)

					console.log('data_first_10:',IdrNalu.slice(0, 10))
					console.log('data_last_10:',IdrNalu.slice(-10))

					newBufferStream = Buffer.concat([newBufferStream,start_code, spsNalu, start_code , ppsNalu, start_code, IdrNalu])
					console.log('sps+pps+Idr Nalu  length:', newBufferStream.length)
					console.log('此时offset',offset,'以及buffer前后',bufferStream.slice(offset-5,offset+5))
				}else{
					//到buffer结尾了
					let otherNalu = bufferStream.slice(offset)//从I帧数据之后直到结尾,不应该添加其它信息,而是加一个p帧头
					newBufferStream = Buffer.concat([newBufferStream,start_code,otherNalu])
					offset = bufferStream.length
				}
				
			}else if(naluType === 5 || naluType === 1){
				//如果是关键帧 或者 P帧/B帧
				data_length = bufferStream.slice(offset,offset + 4).readUInt32BE(0)
				offset = offset + 4
				if(offset + data_length < bufferStream.length){
					//没到buffer结尾
					let IdrNalu = bufferStream.slice(offset, offset + data_length)
					offset = offset + data_length
					// 区分I帧和P帧 p帧是加上3字段的start_code,slice 也是3字段的
					if(naluType === 1){
						newBufferStream = Buffer.concat([newBufferStream,start_code, IdrNalu])

					}else{
						newBufferStream = Buffer.concat([newBufferStream,start_code, IdrNalu])

						// 找到I帧了,直接加上一个P帧头就返回
						console.log('找到I帧了,直接返回')

						return Buffer.concat([newBufferStream,start_code,PB_header])
					}
				}else{
					//到buffer结尾了
					let otherNalu = bufferStream.slice(offset)//从I帧数据之后直到结尾
					newBufferStream = Buffer.concat([newBufferStream,start_code,otherNalu])
					offset = bufferStream.length
				}
			}else {
				console.log('转换结束')
				//如果是其它情况,可能是chunk间隙，数据乱七八糟。加个分隔符结束掉，并且要在后面跟一个P帧标识，这样后面的解码器会认为这是完整的一帧
				let otherNalu = bufferStream.slice(offset)//从I帧数据之后直到结尾
				newBufferStream = Buffer.concat([newBufferStream,start_code,PB_header])
				offset = bufferStream.length
			}
			
			
		}
		console.log('文件buffer结尾了,返回')
		 return newBufferStream
	}

}

// 解析moov盒子
async function Mp4FindMoov(mp4file = ''){
	let start_time = new Date().getTime()
	if(mp4file == ''){
		return -1
	}
	mp4file = path.resolve(mp4file);
	let i = 0;
	let offset = 0
	const MAX_BUFFER_LEN = 1024 * 1024  //1MB 空间
	for(let k =0 ;k < MAX_BUFFER_LEN * 1000; k++){
		let buff = Buffer.alloc(MAX_BUFFER_LEN)
		let filehandle =  await fsPromise.open(mp4file)
		let { buffer , bytesRead} =await filehandle.read(buff, 0, MAX_BUFFER_LEN, offset )
		if(bytesRead == 0){
			return  -1 //'没找到'
		}else{
			let result = 	buffer.indexOf('moov')
			if(result > 0){
				console.log('找到moov啦,( •̀ ω •́ )y',offset + result)
				console.log(`消耗时间:${new Date().getTime() - start_time}ms`)
				return {
					offset:offset + result - 4,
					size:buff.readUInt32BE(result-4),
				}
			}else{
				// 继续下一个循环
			}
		}
		offset += MAX_BUFFER_LEN
	}
	
	

}
module.exports = {
	FindStartCode2:FindStartCode2, 
	FindStartCode3:FindStartCode3,
	getFileInfoAsync:getFileInfoAsync,
	h264_mp4toannexb:h264_mp4toannexb,
	Mp4FindMoov: Mp4FindMoov
}